import os
import yaml
import json
import logging
from datetime import datetime
from typing import Dict, Any, List, Optional


def setup_logger(logger_name: str, log_file: Optional[str] = None) -> logging.Logger:
    """
    设置日志记录器
    
    Args:
        logger_name: 日志记录器名称
        log_file: 日志文件路径，如果为None则只输出到控制台
    
    Returns:
        配置好的日志记录器
    """
    logger = logging.getLogger(logger_name)
    logger.setLevel(logging.INFO)
    
    # 避免重复添加处理器
    if not logger.handlers:
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        
        # 控制台处理器
        console_handler = logging.StreamHandler()
        console_handler.setFormatter(formatter)
        logger.addHandler(console_handler)
        
        # 文件处理器
        if log_file:
            os.makedirs(os.path.dirname(log_file), exist_ok=True)
            file_handler = logging.FileHandler(log_file)
            file_handler.setFormatter(formatter)
            logger.addHandler(file_handler)
    
    return logger


def load_config(config_path: str) -> Dict[str, Any]:
    """
    加载YAML配置文件
    
    Args:
        config_path: 配置文件路径
    
    Returns:
        配置字典
    """
    try:
        with open(config_path, 'r', encoding='utf-8') as f:
            config = yaml.safe_load(f)
        return config
    except Exception as e:
        raise ValueError(f"加载配置文件失败: {str(e)}")


def save_json(data: Any, file_path: str) -> None:
    """
    保存数据为JSON文件
    
    Args:
        data: 要保存的数据
        file_path: 文件路径
    """
    os.makedirs(os.path.dirname(file_path), exist_ok=True)
    with open(file_path, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)


def load_json(file_path: str) -> Any:
    """
    加载JSON文件
    
    Args:
        file_path: 文件路径
    
    Returns:
        加载的数据
    """
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            data = json.load(f)
        return data
    except Exception as e:
        raise ValueError(f"加载JSON文件失败: {str(e)}")


def ensure_directories(directories: List[str]) -> None:
    """
    确保目录存在
    
    Args:
        directories: 目录路径列表
    """
    for directory in directories:
        os.makedirs(directory, exist_ok=True)


def get_timestamp() -> str:
    """
    获取当前时间戳
    
    Returns:
        格式化的时间戳字符串
    """
    return datetime.now().strftime('%Y%m%d_%H%M%S')


def calculate_metrics(y_true, y_pred, y_pred_prob=None) -> Dict[str, float]:
    """
    计算评估指标
    
    Args:
        y_true: 真实标签
        y_pred: 预测标签
        y_pred_prob: 预测概率（可选）
    
    Returns:
        评估指标字典
    """
    from sklearn.metrics import (
        accuracy_score, precision_score, recall_score, f1_score,
        roc_auc_score, confusion_matrix
    )
    
    metrics = {
        'accuracy': accuracy_score(y_true, y_pred),
        'precision': precision_score(y_true, y_pred, average='weighted'),
        'recall': recall_score(y_true, y_pred, average='weighted'),
        'f1_score': f1_score(y_true, y_pred, average='weighted')
    }
    
    # 如果提供了概率预测，计算ROC AUC
    if y_pred_prob is not None and len(set(y_true)) == 2:
        try:
            metrics['roc_auc'] = roc_auc_score(y_true, y_pred_prob)
        except ValueError:
            metrics['roc_auc'] = 0.0
    
    # 计算混淆矩阵
    cm = confusion_matrix(y_true, y_pred)
    metrics['confusion_matrix'] = cm.tolist()
    
    return metrics


def format_response(data: Any, success: bool = True, message: str = "") -> Dict[str, Any]:
    """
    格式化API响应
    
    Args:
        data: 响应数据
        success: 是否成功
        message: 消息
    
    Returns:
        格式化的响应字典
    """
    return {
        'success': success,
        'message': message,
        'data': data,
        'timestamp': get_timestamp()
    }


def validate_device_id(device_id: str) -> bool:
    """
    验证设备ID格式
    
    Args:
        device_id: 设备ID
    
    Returns:
        是否有效
    """
    # 简单的格式验证：ESL-XXX-XXX
    import re
    pattern = r'^ESL-\d{3}-\d{3}$'
    return bool(re.match(pattern, device_id))


def normalize_string(s: str) -> str:
    """
    标准化字符串（去除空格，转为小写）
    
    Args:
        s: 输入字符串
    
    Returns:
        标准化后的字符串
    """
    return s.strip().lower()


def batch_process(items: List[Any], batch_size: int = 100) -> List[List[Any]]:
    """
    批量处理列表
    
    Args:
        items: 要处理的列表
        batch_size: 批次大小
    
    Returns:
        批次列表
    """
    return [items[i:i + batch_size] for i in range(0, len(items), batch_size)]


def filter_features_by_importance(feature_importance: Dict[str, float], 
                                 threshold: float = 0.01) -> List[str]:
    """
    根据特征重要性过滤特征
    
    Args:
        feature_importance: 特征重要性字典
        threshold: 阈值
    
    Returns:
        重要特征列表
    """
    return [feature for feature, importance in feature_importance.items() 
            if importance >= threshold]


def log_model_performance(model_name: str, metrics: Dict[str, float], 
                          logger: Optional[logging.Logger] = None) -> None:
    """
    记录模型性能指标
    
    Args:
        model_name: 模型名称
        metrics: 性能指标
        logger: 日志记录器
    """
    log_message = f"模型性能 - {model_name}:\n"
    for key, value in metrics.items():
        if key != 'confusion_matrix':
            log_message += f"  {key}: {value:.4f}\n"
    
    if logger:
        logger.info(log_message)
    else:
        print(log_message)


def get_device_info_from_cache(device_id: str, cache_dir: str) -> Optional[Dict[str, Any]]:
    """
    从缓存获取设备信息
    
    Args:
        device_id: 设备ID
        cache_dir: 缓存目录
    
    Returns:
        设备信息字典，如果不存在返回None
    """
    cache_file = os.path.join(cache_dir, f"device_{device_id}.json")
    if os.path.exists(cache_file):
        try:
            return load_json(cache_file)
        except Exception:
            return None
    return None


def cache_device_info(device_id: str, device_info: Dict[str, Any], cache_dir: str) -> None:
    """
    缓存设备信息
    
    Args:
        device_id: 设备ID
        device_info: 设备信息
        cache_dir: 缓存目录
    """
    cache_file = os.path.join(cache_dir, f"device_{device_id}.json")
    save_json(device_info, cache_file)
